/**
 * Copyright (c) 2011 Basil Shikin, VintageRadio Project
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.vintagephone.model;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.vintagephone.model.hardware.RadioHardwareControl;
import org.vintagephone.model.player.Player.NextSongCallback;
import org.vintagephone.model.player.PlayerControl;
import org.vintagephone.model.player.PlayerUtils;
import org.vintagephone.model.podcaster.Podcaster;
import org.vintagephone.view.flat.RadioDialController;

import android.content.Context;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.view.View;

/**
 * This class manages radio lifecycle. It is used to respond to events
 * that are generated from the player, UI and hardware.
 * 
 * @author Basil Shikin
 *
 */
public class RadioLifecycle 
{
    private static final String Tag = "RadioLifecycle";
    
    
	private final static ExecutorService s_operationExecutor;
	
	
	static
	{
		s_operationExecutor  = Executors.newSingleThreadExecutor();
	}
	
	// Parent objects
	private final Context m_context;
	
	// Controlled objects
	private final PlayerControl        m_playerControl;
	private final RadioDialController  m_viewControl;
	private final RadioHardwareControl m_hardwareControl;
	private final Podcaster            m_podcaster;
	
	private final ControlListener m_controlListener;
	
    private WakeLock m_wakeLock;

	public RadioLifecycle( Context context )
	{
	    m_context = context;
	    
		m_playerControl = new PlayerControl(context);
		m_viewControl = new RadioDialController( context );
		m_hardwareControl = new RadioHardwareControl();
		m_podcaster = new Podcaster( PlayerUtils.resolveFolderFile( MusicFolder.FOUR ) );
		
		m_controlListener = new ControlListener();
	}
	
	public void initialize()
	{
	    final PowerManager pm = (PowerManager)m_context.getSystemService( Context.POWER_SERVICE );
        m_wakeLock = pm.newWakeLock( PowerManager.FULL_WAKE_LOCK
                                   | PowerManager.ACQUIRE_CAUSES_WAKEUP                
                                   | PowerManager.ON_AFTER_RELEASE, Tag );
        
		m_playerControl.initialize();
		m_viewControl.initialize();
		m_hardwareControl.initialize();
		m_podcaster.initialize();
		
		switchToFolder( MusicFolder.ONE ); // Select fist folder as default

		m_playerControl.setNextSongCallback( m_controlListener );
		m_viewControl.setListener( m_controlListener );
		m_hardwareControl.setListener( m_controlListener );
	}
	
	public View getView() 
	{
		return m_viewControl.getView();
	}
	
	private void switchToFolder( final MusicFolder folder )
	{
	    final Song song = m_playerControl.switchToFolder( folder );
		
		m_viewControl.setScreenSongs(folder.ordinal(), m_playerControl.getActiveFolderSongs() );
		m_viewControl.switchToScreen( folder.ordinal() );
		m_viewControl.switchToSong( song );
	}
	
	private class ControlListener
		implements RadioControlListener, NextSongCallback
	{
        public void switchToNextSong()
        {
            songChanged( true );
        }

        public void songChanged(final boolean playNext) 
		{
			s_operationExecutor.execute( new Runnable() {
				public void run() 
				{
				    if ( !m_wakeLock.isHeld() ) m_wakeLock.acquire();
				    
					if ( playNext )
					{
					    final Song song = m_playerControl.switchToNextSong();
						m_viewControl.switchToSong( song );
					}
					else
					{
					    final Song song = m_playerControl.switchToPreviousSong();
						m_viewControl.switchToSong( song );
					}
				}
			} );
		}

		public void folderChanged(final int buttonNumber) 
		{
			s_operationExecutor.execute( new Runnable() {
				public void run() 
				{
				    if ( !m_wakeLock.isHeld() ) m_wakeLock.acquire();
				    
					final MusicFolder folder = MusicFolder.values()[ buttonNumber ];
					
					switchToFolder( folder );
				}
			} ); 
		}

		public void offStateChaneged(final boolean isOff) 
		{
		    s_operationExecutor.execute( new Runnable() {
                public void run() 
                {
                    if ( isOff )
                    {
                        if ( m_wakeLock.isHeld() )  m_wakeLock.release();
                    }
                    else
                    {
                        if ( !m_wakeLock.isHeld() ) m_wakeLock.acquire();
                    }
                    
                    m_viewControl.setOff( isOff );
                    
                    final Song song = m_playerControl.setIsOn( !isOff );
                    if ( song != null )
                    {
                        m_viewControl.switchToSong( song );
                    }
                }
            } );
		}

		public void volumeChanged(final int percent) 
		{
		    s_operationExecutor.execute( new Runnable() {
                public void run() 
                {
                    if ( !m_wakeLock.isHeld() ) m_wakeLock.acquire();
                    
                    m_viewControl.setVolume( percent );
                    m_playerControl.setVolume( percent );
                }
            } );
		}
	}
}
